<?php

namespace App\Services\Bank\BankOfHangzhou;

use App\Services\Bank\BankServiceInterface;
use App\Models\BankDetailHangzhou;
use App\Models\Recharge;
use App\Models\Tenant;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class BankOfHangzhouService implements BankServiceInterface
{
    private BankOfHangzhouClient $client;

    public function __construct(BankOfHangzhouClient $client)
    {
        $this->client = $client;
    }

    /**
     * 联行号增量同步 (BY0012)
     *
     * @param string $queryDate 同步日期 (yyyy-MM-dd)
     * @return array
     */
    public function syncBankNumbers(string $queryDate): array
    {
        Log::info('Starting bank numbers sync', [
            'operation' => 'SYNC_BANK_NUMBERS',
            'query_date' => $queryDate,
            'bank' => 'BankOfHangzhou',
        ]);

        $mapData = [
            'queryDate' => $queryDate,
        ];

        $result = $this->client->callApi('BANK_SYNC', $mapData);

        if ($result['success']) {
            Log::info('Bank numbers sync completed successfully', [
                'operation' => 'SYNC_BANK_NUMBERS',
                'query_date' => $queryDate,
                'count' => count($result['loop_data']),
                'ret_code' => $result['ret_code'],
                'bank' => 'BankOfHangzhou',
            ]);
        } else {
            Log::warning('Bank numbers sync failed', [
                'operation' => 'SYNC_BANK_NUMBERS',
                'query_date' => $queryDate,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);
        }

        return $result;
    }

    /**
     * 联行号查询 (BY0004)
     *
     * @param string $bankName 行名关键字 (必填)
     * @param string|null $bankTypeName 行类型名称 (选填)
     * @param string|null $isPreciseQuery 是否精确查询 (1-精确，0-模糊，默认模糊)
     * @return array
     */
    public function queryBankNumbers(string $bankName, ?string $bankTypeName = null, ?string $isPreciseQuery = '0'): array
    {
        $mapData = [
            'bankName' => $bankName,
        ];

        if ($bankTypeName !== null) {
            $mapData['bankTypeName'] = $bankTypeName;
        }

        if ($isPreciseQuery !== null) {
            $mapData['isPreciseQuery'] = $isPreciseQuery;
        }

        Log::info('Starting bank numbers query', [
            'operation' => 'QUERY_BANK_NUMBERS',
            'bank_name' => $bankName,
            'bank_type_name' => $bankTypeName,
            'is_precise_query' => $isPreciseQuery,
            'bank' => 'BankOfHangzhou',
        ]);

        $result = $this->client->callApi('BANK_QUERY', $mapData);

        if ($result['success']) {
            Log::info('Bank numbers query completed successfully', [
                'operation' => 'QUERY_BANK_NUMBERS',
                'bank_name' => $bankName,
                'bank_type_name' => $bankTypeName,
                'count' => count($result['loop_data']),
                'ret_code' => $result['ret_code'],
                'bank' => 'BankOfHangzhou',
            ]);
        } else {
            Log::warning('Bank numbers query failed', [
                'operation' => 'QUERY_BANK_NUMBERS',
                'bank_name' => $bankName,
                'bank_type_name' => $bankTypeName,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);
        }

        return $result;
    }

    /**
     * 余额查询 (BY0007)
     */
    public function queryBalance(string $bankAcc): array
    {
        $bankAcc = trim($bankAcc);
        if ($bankAcc === '') {
            throw new \InvalidArgumentException('银行账号不能为空');
        }

        Log::info('Starting balance query', [
            'operation' => 'BALANCE_QUERY',
            'bank_acc' => $bankAcc,
            'bank' => 'BankOfHangzhou',
        ]);

        $result = $this->client->callApi('BALANCE_QUERY', [], [
            ['bankAcc' => $bankAcc],
        ]);

        if (!$result['success']) {
            Log::warning('Balance query failed', [
                'operation' => 'BALANCE_QUERY',
                'bank_acc' => $bankAcc,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);

            throw new \RuntimeException($result['ret_msg'] ?? '余额查询失败');
        }

        $balances = $this->extractBalances($result);

        Log::info('Balance query completed successfully', [
            'operation' => 'BALANCE_QUERY',
            'bank_acc' => $bankAcc,
            'balance' => $balances['balance'],
            'available_balance' => $balances['available_balance'],
            'ret_code' => $result['ret_code'],
            'bank' => 'BankOfHangzhou',
        ]);

        return $balances;
    }

    private function extractBalances(array $result): array
    {
        $row = $result['loop_data'][0] ?? [];

        $balance = $this->toAmount($row['bankBal'] ?? null);
        $available = $this->toAmount($row['availBal'] ?? null);

        return [
            'balance' => $balance,
            'available_balance' => $available,
        ];
    }

    private function toAmount($value): ?float
    {
        if ($value === null) {
            return null;
        }

        if (is_string($value)) {
            $value = str_replace(',', '', $value);
        }

        return is_numeric($value) ? (float) $value : null;
    }

    /**
     * 批量代发 (BY0008)
     *
     * @param string $erpBatchNo ERP批次号 (必填，保证唯一)
     * @param string $wageTitle 发放标题 (必填)
     * @param string $busiType 发放业务类型 (必填: 1-工资, 2-股权基金分红, 3-其他)
     * @param array $payDetails 付款明细数组
     * @param array $options 其他选项
     * @return array
     */
    public function batchPay(string $erpBatchNo, string $wageTitle, string $busiType, array $payDetails, array $options = []): array
    {
        // 计算总金额和总笔数
        $totalMoney = number_format(array_sum(array_column($payDetails, 'amt')), 2, '.', '');
        $totalCount = count($payDetails);

        $mapData = [
            'erpBatchNo' => $erpBatchNo,
            'wageTitle' => $wageTitle,
            'busiType' => $busiType,
            'totalMoney' => $totalMoney,
            'totalCount' => $totalCount,
        ];

        // 设置可选参数
        $optionalFields = [
            'payerAccNo', 'payerCorpCode', 'payerCorpName', 'erpPayerCorpCode',
            'payFlow', 'rmk', 'showDetail', 'erpReqUser'
        ];

        foreach ($optionalFields as $field) {
            if (isset($options[$field])) {
                $mapData[$field] = $options[$field];
            }
        }

        // 设置默认值
        $mapData['payFlow'] = $mapData['payFlow'] ?? '1'; // 默认待审批
        $mapData['showDetail'] = $mapData['showDetail'] ?? '1'; // 默认显示

        // 设置默认付款人信息（如果未提供）
        if (empty($mapData['payerCorpCode']) && empty($mapData['payerCorpName']) && empty($mapData['erpPayerCorpCode'])) {
            $mapData['payerCorpName'] = config('bank.banks.BankOfHangzhou.payer_corp_name');
            $mapData['payerCorpCode'] = config('bank.banks.BankOfHangzhou.payer_corp_code');
        }

        // 设置默认付款账号（如果未提供）
        if (empty($mapData['payerAccNo'])) {
            $mapData['payerAccNo'] = config('bank.banks.BankOfHangzhou.payer_acc_no');
        }

        Log::info('Starting batch pay submission', [
            'operation' => 'BATCH_PAY',
            'erp_batch_no' => $erpBatchNo,
            'wage_title' => $wageTitle,
            'busi_type' => $busiType,
            'detail_count' => count($payDetails),
            'pay_flow' => $mapData['payFlow'],
            'bank' => 'BankOfHangzhou',
        ]);

        $result = $this->client->callApi('BATCH_PAY', $mapData, $payDetails);

        if ($result['success']) {
            Log::info('Batch pay submitted successfully', [
                'operation' => 'BATCH_PAY',
                'erp_batch_no' => $erpBatchNo,
                'wage_title' => $wageTitle,
                'detail_count' => count($payDetails),
                'ret_code' => $result['ret_code'],
                'batch_no' => $result['map_data']['batchNo'] ?? null,
                'bank' => 'BankOfHangzhou',
            ]);
        } else {
            Log::error('Batch pay submission failed', [
                'operation' => 'BATCH_PAY',
                'erp_batch_no' => $erpBatchNo,
                'wage_title' => $wageTitle,
                'detail_count' => count($payDetails),
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);
        }

        return $result;
    }

    /**
     * 代发结果查询 (BY0009)
     *
     * @param string|null $erpBatchNo ERP批次号
     * @param string|null $startDate 开始日期 (yyyy-MM-dd)
     * @param string|null $endDate 结束日期 (yyyy-MM-dd)
     * @return array
     */
    public function queryPayResult(?string $erpBatchNo = null, ?string $startDate = null, ?string $endDate = null): array
    {
        $mapData = [];

        if ($erpBatchNo !== null) {
            $mapData['wageNo'] = $erpBatchNo;
        }

        if ($startDate !== null) {
            $mapData['startDate'] = $startDate;
        }

        if ($endDate !== null) {
            $mapData['endDate'] = $endDate;
        }

        Log::info('Starting pay result query', [
            'operation' => 'QUERY_PAY_RESULT',
            'erp_batch_no' => $erpBatchNo,
            'start_date' => $startDate,
            'end_date' => $endDate,
            'bank' => 'BankOfHangzhou',
        ]);

        $result = $this->client->callApi('PAY_RESULT_QUERY', $mapData);

        if ($result['success']) {
            Log::info('Pay result query completed successfully', [
                'operation' => 'QUERY_PAY_RESULT',
                'erp_batch_no' => $erpBatchNo,
                'start_date' => $startDate,
                'end_date' => $endDate,
                'count' => count($result['loop_data']),
                'ret_code' => $result['ret_code'],
                'bank' => 'BankOfHangzhou',
            ]);
        } else {
            Log::warning('Pay result query failed', [
                'operation' => 'QUERY_PAY_RESULT',
                'erp_batch_no' => $erpBatchNo,
                'start_date' => $startDate,
                'end_date' => $endDate,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);
        }

        return $result;
    }

    /**
     * 回单批量申请 (BY0010)
     *
     * @param array $receiptRequests 回单申请数组
     * @return array
     */
    public function batchApplyReceipt(string $compFlowNo, string $beginDate, string $endDate, array $bankAccounts): array
    {
        $bankAccounts = array_values(array_filter(array_map('trim', $bankAccounts), static fn ($acc) => $acc !== ''));

        if (empty($bankAccounts)) {
            throw new \InvalidArgumentException('银行账号列表不能为空');
        }

        $mapData = [
            'compFlowNo' => $compFlowNo,
            'beginDate' => $beginDate,
            'endDate' => $endDate,
        ];

        $loopData = array_map(static fn (string $acc) => ['bankAcc' => $acc], $bankAccounts);

        Log::info('Starting batch receipt application', [
            'operation' => 'BATCH_APPLY_RECEIPT',
            'comp_flow_no' => $compFlowNo,
            'begin_date' => $beginDate,
            'end_date' => $endDate,
            'bank_accounts' => $bankAccounts,
            'bank' => 'BankOfHangzhou',
        ]);

        $result = $this->client->callApi('RECEIPT_BATCH_APPLY', $mapData, $loopData);

        if ($result['success']) {
            Log::info('Batch receipt application completed successfully', [
                'operation' => 'BATCH_APPLY_RECEIPT',
                'comp_flow_no' => $compFlowNo,
                'begin_date' => $beginDate,
                'end_date' => $endDate,
                'ret_code' => $result['ret_code'],
                'bank' => 'BankOfHangzhou',
            ]);
        } else {
            Log::warning('Batch receipt application failed', [
                'operation' => 'BATCH_APPLY_RECEIPT',
                'comp_flow_no' => $compFlowNo,
                'begin_date' => $beginDate,
                'end_date' => $endDate,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);
        }

        return $result;
    }

    /**
     * 单笔回单下载 (BY0066)
     *
     * @param string $receiptNo 回单号
     * @return array
     */
    public function downloadSingleReceipt(string $serialNo): array
    {
        $mapData = [
            'serialNo' => $serialNo,
        ];

        Log::info('Starting single receipt download', [
            'operation' => 'DOWNLOAD_SINGLE_RECEIPT',
            'serial_no' => $serialNo,
            'bank' => 'BankOfHangzhou',
        ]);

        $result = $this->client->callApi('RECEIPT_DOWNLOAD', $mapData);

        if ($result['success']) {
            Log::info('Single receipt download completed successfully', [
                'operation' => 'DOWNLOAD_SINGLE_RECEIPT',
                'serial_no' => $serialNo,
                'ret_code' => $result['ret_code'],
                'has_receipt_data' => !empty($result['map_data']['receiptData']),
                'bank' => 'BankOfHangzhou',
            ]);
        } else {
            Log::warning('Single receipt download failed', [
                'operation' => 'DOWNLOAD_SINGLE_RECEIPT',
                'serial_no' => $serialNo,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);
        }

        return $result;
    }

    /**
     * 当日明细查询 (BY0005)
     *
     * @param string $bankAcc 待查询账号 (必填)
     * @param float|null $queryAmtBegin 金额范围起 (选填)
     * @param float|null $queryAmtEnd 金额范围止 (选填)
     * @param string|null $queryCdSign 收支方向 (选填: 0-收入, 1-支出)
     * @param string|null $expandFields 额外字段 (选填，以|分隔，如: serialNo)
     * @return array
     */
    public function queryDailyDetails(string $bankAcc, ?float $queryAmtBegin = null, ?float $queryAmtEnd = null, ?string $queryCdSign = null, ?string $expandFields = null): array
    {
        $mapData = [
            'bankAcc' => $bankAcc,
        ];

        if ($queryAmtBegin !== null) {
            $mapData['queryAmtBegin'] = number_format($queryAmtBegin, 2, '.', '');
        }

        if ($queryAmtEnd !== null) {
            $mapData['queryAmtEnd'] = number_format($queryAmtEnd, 2, '.', '');
        }

        if ($queryCdSign !== null) {
            $mapData['queryCdSign'] = $queryCdSign;
        }

        if ($expandFields !== null) {
            $mapData['expandFields'] = $expandFields;
        }

        Log::info('Starting daily detail query', [
            'operation' => 'QUERY_DAILY_DETAILS',
            'bank_acc' => $bankAcc,
            'query_amt_begin' => $queryAmtBegin,
            'query_amt_end' => $queryAmtEnd,
            'query_cd_sign' => $queryCdSign,
            'expand_fields' => $expandFields,
            'bank' => 'BankOfHangzhou',
        ]);

        $result = $this->client->callApi('DAILY_DETAIL_QUERY', $mapData);

        if ($result['success']) {
            Log::info('Daily detail query completed successfully', [
                'operation' => 'QUERY_DAILY_DETAILS',
                'bank_acc' => $bankAcc,
                'count' => count($result['loop_data']),
                'record_total' => $result['map_data']['recordTotal'] ?? 0,
                'ret_code' => $result['ret_code'],
                'bank' => 'BankOfHangzhou',
            ]);
        } else {
            Log::warning('Daily detail query failed', [
                'operation' => 'QUERY_DAILY_DETAILS',
                'bank_acc' => $bankAcc,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);
        }

        return $result;
    }

    /**
     * 历史明细查询 (BY0006)
     *
     * @param string $bankAcc 待查询账号 (必填)
     * @param string $queryDateBegin 查询开始日期 (必填，格式: YYYY-MM-DD)
     * @param string $queryDateEnd 查询结束日期 (必填，格式: YYYY-MM-DD)
     * @param float|null $queryAmtBegin 金额范围起 (选填)
     * @param float|null $queryAmtEnd 金额范围止 (选填)
     * @param string|null $queryCdSign 收支方向 (选填: 0-收入, 1-支出)
     * @param string|null $expandFields 额外字段 (选填，以|分隔，如: serialNo)
     * @return array
     */
    public function queryHistoryDetails(string $bankAcc, string $queryDateBegin, string $queryDateEnd, ?float $queryAmtBegin = null, ?float $queryAmtEnd = null, ?string $queryCdSign = null, ?string $expandFields = null): array
    {
        $mapData = [
            'bankAcc' => $bankAcc,
            'queryDateBegin' => $queryDateBegin,
            'queryDateEnd' => $queryDateEnd,
        ];

        if ($queryAmtBegin !== null) {
            $mapData['queryAmtBegin'] = number_format($queryAmtBegin, 2, '.', '');
        }

        if ($queryAmtEnd !== null) {
            $mapData['queryAmtEnd'] = number_format($queryAmtEnd, 2, '.', '');
        }

        if ($queryCdSign !== null) {
            $mapData['queryCdSign'] = $queryCdSign;
        }

        if ($expandFields !== null) {
            $mapData['expandFields'] = $expandFields;
        }

        Log::info('Starting history detail query', [
            'operation' => 'QUERY_HISTORY_DETAILS',
            'bank_acc' => $bankAcc,
            'query_date_begin' => $queryDateBegin,
            'query_date_end' => $queryDateEnd,
            'query_amt_begin' => $queryAmtBegin,
            'query_amt_end' => $queryAmtEnd,
            'query_cd_sign' => $queryCdSign,
            'expand_fields' => $expandFields,
            'bank' => 'BankOfHangzhou',
        ]);

        $result = $this->client->callApi('HISTORY_DETAIL_QUERY', $mapData);

        if ($result['success']) {
            Log::info('History detail query completed successfully', [
                'operation' => 'QUERY_HISTORY_DETAILS',
                'bank_acc' => $bankAcc,
                'query_date_begin' => $queryDateBegin,
                'query_date_end' => $queryDateEnd,
                'count' => count($result['loop_data']),
                'record_total' => $result['map_data']['recordTotal'] ?? 0,
                'ret_code' => $result['ret_code'],
                'bank' => 'BankOfHangzhou',
            ]);
        } else {
            Log::warning('History detail query failed', [
                'operation' => 'QUERY_HISTORY_DETAILS',
                'bank_acc' => $bankAcc,
                'query_date_begin' => $queryDateBegin,
                'query_date_end' => $queryDateEnd,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
                'bank' => 'BankOfHangzhou',
            ]);
        }

        return $result;
    }

    /**
     * 获取昨天的日期字符串 (用于联行号同步)
     *
     * @return string
     */
    public function getYesterdayDateString(): string
    {
        return Carbon::yesterday()->format('Y-m-d');
    }

    /**
     * 格式化日期为银行API要求的格式
     *
     * @param Carbon|string $date
     * @return string
     */
    public function formatDate($date): string
    {
        if ($date instanceof Carbon) {
            return $date->format('Y-m-d');
        }

        return Carbon::parse($date)->format('Y-m-d');
    }

    /**
     * 验证批量代发明细数据格式
     *
     * @param array $payDetails
     * @return array 返回验证结果和错误信息
     */
    public function validatePayDetails(array $payDetails): array
    {
        $errors = [];

        foreach ($payDetails as $index => $detail) {
            // 验证银行API必填字段
            $requiredFields = ['empNo', 'userName', 'bankAcc', 'amt', 'purpose'];

            foreach ($requiredFields as $field) {
                if (!isset($detail[$field]) || empty($detail[$field])) {
                    $errors[] = "明细 {$index}: 字段 {$field} 为必填项";
                }
            }

            // 验证金额格式
            if (isset($detail['amt'])) {
                if (!is_numeric($detail['amt']) || $detail['amt'] <= 0) {
                    $errors[] = "明细 {$index}: 金额必须为正数";
                }
            }
        }

        return [
            'valid' => empty($errors),
            'errors' => $errors,
        ];
    }

    /**
     * 批处理异常状态检查
     * 根据文档说明，BY0003接口返回retCode=2时仅代表查询失败，不代表付款失败
     *
     * @param array $result
     * @return string pending|success|failed|suspicious
     */
    public function getPaymentStatus(array $result): string
    {
        if (!isset($result['ret_code'])) {
            return 'failed';
        }

        switch ($result['ret_code']) {
            case '0':
                return 'success';
            case '2':
                // 根据文档建议，查询返回2时置为存疑状态
                return 'suspicious';
            default:
                return 'failed';
        }
    }

    /**
     * 同步银行明细到数据库
     *
     * @param string $bankAcc 银行账号
     * @param int $days 同步天数，1表示当日，大于1表示历史明细
     * @param string|null $syncBatchId 同步批次ID，为空则自动生成
     * @return array 返回同步结果
     */
    public function syncDetailsToDatabase(string $bankAcc, int $days = 1, ?string $syncBatchId = null): array
    {
        $syncBatchId = $syncBatchId ?: $this->generateSyncBatchId();

        Log::info('开始同步银行明细到数据库', [
            'operation' => 'SYNC_DETAILS_TO_DATABASE',
            'bank_acc' => $bankAcc,
            'days' => $days,
            'sync_batch_id' => $syncBatchId,
            'bank' => 'BankOfHangzhou',
        ]);

        $totalSynced = 0;
        $totalErrors = 0;
        $results = [];

        try {
            if ($days === 1) {
                // 同步当日明细
                $result = $this->syncDailyDetailsToDatabase($bankAcc, $syncBatchId);
                $results['daily'] = $result;
                $totalSynced += $result['synced_count'];
                $totalErrors += $result['error_count'];
            } else {
                // 同步历史明细（分批查询，每次最多31天）
                $endDate = Carbon::today();
                $startDate = $endDate->copy()->subDays($days - 1);

                // 按31天分批查询
                while ($startDate->lte($endDate)) {
                    $batchEndDate = $startDate->copy()->addDays(30);
                    if ($batchEndDate->gt($endDate)) {
                        $batchEndDate = $endDate;
                    }

                    $result = $this->syncHistoryDetailsToDatabase(
                        $bankAcc,
                        $startDate->format('Y-m-d'),
                        $batchEndDate->format('Y-m-d'),
                        $syncBatchId
                    );

                    $results["history_{$startDate->format('Y-m-d')}_to_{$batchEndDate->format('Y-m-d')}"] = $result;
                    $totalSynced += $result['synced_count'];
                    $totalErrors += $result['error_count'];

                    $startDate = $batchEndDate->copy()->addDay();
                }
            }

            Log::info('银行明细同步完成', [
                'operation' => 'SYNC_DETAILS_TO_DATABASE',
                'sync_batch_id' => $syncBatchId,
                'total_synced' => $totalSynced,
                'total_errors' => $totalErrors,
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => true,
                'sync_batch_id' => $syncBatchId,
                'total_synced' => $totalSynced,
                'total_errors' => $totalErrors,
                'details' => $results,
            ];

        } catch (\Exception $e) {
            Log::error('银行明细同步失败', [
                'operation' => 'SYNC_DETAILS_TO_DATABASE',
                'sync_batch_id' => $syncBatchId,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => false,
                'sync_batch_id' => $syncBatchId,
                'error' => $e->getMessage(),
                'total_synced' => $totalSynced,
                'total_errors' => $totalErrors + 1,
            ];
        }
    }

    /**
     * 获取同步统计信息
     *
     * @param string|null $syncBatchId 指定批次ID，为空则获取最新批次
     * @return array
     */
    public function getSyncStats(?string $syncBatchId = null): array
    {
        if ($syncBatchId) {
            $query = BankDetailHangzhou::where('sync_batch_id', $syncBatchId);
        } else {
            // 获取最新批次
            $latestBatch = BankDetailHangzhou::orderBy('synced_at', 'desc')->first();
            if (!$latestBatch) {
                return ['error' => '没有找到同步记录'];
            }
            $query = BankDetailHangzhou::where('sync_batch_id', $latestBatch->sync_batch_id);
        }

        $stats = $query->selectRaw('
            COUNT(*) as total_count,
            SUM(CASE WHEN match_status = "unmatched" THEN 1 ELSE 0 END) as unmatched_count,
            SUM(CASE WHEN match_status = "matched" THEN 1 ELSE 0 END) as matched_count,
            SUM(CASE WHEN match_status = "ignored" THEN 1 ELSE 0 END) as ignored_count,
            SUM(amt) as total_amount,
            MIN(synced_at) as sync_start_time,
            MAX(synced_at) as sync_end_time,
            MAX(sync_batch_id) as sync_batch_id
        ')->first();

        return $stats ? $stats->toArray() : ['error' => '没有找到同步记录'];
    }

    /**
     * 同步当日明细到数据库
     *
     * @param string $bankAcc 银行账号
     * @param string $syncBatchId 同步批次ID
     * @return array
     */
    private function syncDailyDetailsToDatabase(string $bankAcc, string $syncBatchId): array
    {
        try {
            // 查询收入明细（充值相关）
            $result = $this->queryDailyDetails(
                $bankAcc,
                null, // queryAmtBegin
                null, // queryAmtEnd
                '0', // queryCdSign: 收入
                'serialNo|voucherNo' // expandFields
            );

            return $this->processBankApiResult($result, $syncBatchId, 'daily');

        } catch (\Exception $e) {
            Log::error('当日明细同步失败', [
                'operation' => 'SYNC_DAILY_DETAILS_TO_DATABASE',
                'bank_acc' => $bankAcc,
                'sync_batch_id' => $syncBatchId,
                'error' => $e->getMessage(),
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => false,
                'synced_count' => 0,
                'error_count' => 1,
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * 同步历史明细到数据库
     *
     * @param string $bankAcc 银行账号
     * @param string $startDate 开始日期
     * @param string $endDate 结束日期
     * @param string $syncBatchId 同步批次ID
     * @return array
     */
    private function syncHistoryDetailsToDatabase(string $bankAcc, string $startDate, string $endDate, string $syncBatchId): array
    {
        try {
            // 查询所有明细（暂时测试用）
            $result = $this->queryHistoryDetails(
                $bankAcc,
                $startDate,
                $endDate,
                null, // queryAmtBegin
                null, // queryAmtEnd
                null, // queryCdSign: 所有类型
                'serialNo|voucherNo' // expandFields
            );

            return $this->processBankApiResult($result, $syncBatchId, 'history');

        } catch (\Exception $e) {
            Log::error('历史明细同步失败', [
                'operation' => 'SYNC_HISTORY_DETAILS_TO_DATABASE',
                'bank_acc' => $bankAcc,
                'start_date' => $startDate,
                'end_date' => $endDate,
                'sync_batch_id' => $syncBatchId,
                'error' => $e->getMessage(),
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => false,
                'synced_count' => 0,
                'error_count' => 1,
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * 处理银行API返回结果并保存到数据库
     *
     * @param array $apiResult 银行API返回结果
     * @param string $syncBatchId 同步批次ID
     * @param string $type 同步类型
     * @return array
     */
    private function processBankApiResult(array $apiResult, string $syncBatchId, string $type): array
    {
        if (!$apiResult['success']) {
            return [
                'success' => false,
                'synced_count' => 0,
                'error_count' => 1,
                'error' => $apiResult['ret_msg'] ?? '银行API调用失败',
                'ret_code' => $apiResult['ret_code'] ?? 'unknown',
            ];
        }

        $details = $apiResult['loop_data'] ?? [];
        $syncedCount = 0;
        $errorCount = 0;
        $duplicateCount = 0;

        DB::transaction(function () use ($details, $syncBatchId, &$syncedCount, &$errorCount, &$duplicateCount) {
            foreach ($details as $detail) {
                try {
                    // 检查是否已存在（基于流水号去重）
                    if (!empty($detail['serialNo'])) {
                        $existing = BankDetailHangzhou::where('serial_no', $detail['serialNo'])->first();
                        if ($existing) {
                            $duplicateCount++;
                            Log::debug('银行明细已存在，跳过', [
                                'serial_no' => $detail['serialNo'],
                                'existing_id' => $existing->id,
                                'bank' => 'BankOfHangzhou',
                            ]);
                            continue;
                        }
                    }

                    // 创建新记录
                    BankDetailHangzhou::createFromApiData($detail, $syncBatchId);
                    $syncedCount++;

                    Log::debug('银行明细同步成功', [
                        'serial_no' => $detail['serialNo'] ?? 'unknown',
                        'amount' => $detail['amt'] ?? 0,
                        'sync_batch_id' => $syncBatchId,
                        'bank' => 'BankOfHangzhou',
                    ]);

                } catch (\Exception $e) {
                    $errorCount++;
                    Log::error('银行明细同步失败', [
                        'detail' => $detail,
                        'sync_batch_id' => $syncBatchId,
                        'error' => $e->getMessage(),
                        'bank' => 'BankOfHangzhou',
                    ]);
                }
            }
        });

        Log::info("{$type}明细同步完成", [
            'operation' => "SYNC_{$type}_DETAILS_TO_DATABASE",
            'sync_batch_id' => $syncBatchId,
            'total_details' => count($details),
            'synced_count' => $syncedCount,
            'duplicate_count' => $duplicateCount,
            'error_count' => $errorCount,
            'bank' => 'BankOfHangzhou',
        ]);

        return [
            'success' => true,
            'synced_count' => $syncedCount,
            'error_count' => $errorCount,
            'duplicate_count' => $duplicateCount,
            'total_details' => count($details),
            'ret_code' => $apiResult['ret_code'] ?? '0',
        ];
    }

    /**
     * 生成同步批次ID
     *
     * @return string
     */
    private function generateSyncBatchId(): string
    {
        return 'hangzhou_' . date('YmdHis') . '_' . Str::random(6);
    }

    /**
     * 执行充值匹配算法
     *
     * @param array $options 匹配选项
     * @return array 返回匹配结果
     */
    public function runRechargeMatching(array $options = []): array
    {
        try {
            Log::info('开始执行充值匹配算法', [
                'operation' => 'RUN_RECHARGE_MATCHING',
                'options' => $options,
                'bank' => 'BankOfHangzhou',
            ]);

            // 获取待匹配的充值申请
            $pendingRecharges = Recharge::where('status', Recharge::STATUS_PENDING)
                ->orWhere('status', Recharge::STATUS_PROCESSING)
                ->get();

            // 获取未匹配的银行明细
            $unmatchedDetails = BankDetailHangzhou::unmatched()
                ->income() // 只匹配收入明细
                ->orderBy('transaction_datetime', 'desc')
                ->get();

            $matchResults = [];
            $matchedCount = 0;

            foreach ($pendingRecharges as $recharge) {
                // 更新充值状态为处理中
                $recharge->update(['status' => Recharge::STATUS_PROCESSING]);

                $bestMatch = $this->findBestMatch($recharge, $unmatchedDetails);

                if ($bestMatch && $bestMatch['confidence'] >= 0.6) {
                    $detail = $bestMatch['detail'];

                    DB::transaction(function () use ($detail, $recharge, $bestMatch) {
                        // 标记银行明细匹配
                        $detail->markAsMatched($recharge->id, $bestMatch['confidence']);

                        // 更新充值记录
                        $recharge->status = Recharge::STATUS_MATCHED;
                        $recharge->matched_detail_id = $detail->id;
                        $recharge->matched_bank = 'BankOfHangzhou';
                        $recharge->save();

                        // 调整租户余额/可开票金额
                        $tenant = Tenant::query()->lockForUpdate()->find($recharge->tenant_id);
                        if ($tenant) {
                            $amount = (string) ($recharge->amount ?? '0');
                            $tenant->account_balance = bcadd((string) ($tenant->account_balance ?? '0'), $amount, 2);
                            $tenant->invoiceable_amount = bcadd((string) ($tenant->invoiceable_amount ?? '0'), $amount, 2);
                            $tenant->save();
                        }
                    });

                    $matchResults[] = [
                        'recharge_id' => $recharge->id,
                        'recharge_number' => $recharge->recharge_number,
                        'bank_detail_id' => $detail->id,
                        'confidence' => $bestMatch['confidence'],
                        'match_type' => 'auto',
                        'status' => 'matched'
                    ];

                    $matchedCount++;

                    // 从未匹配列表中移除已匹配的明细
                    $unmatchedDetails = $unmatchedDetails->filter(function ($item) use ($detail) {
                        return $item->id !== $detail->id;
                    });

                    Log::info('充值匹配成功', [
                        'recharge_id' => $recharge->id,
                        'bank_detail_id' => $detail->id,
                        'confidence' => $bestMatch['confidence'],
                        'bank' => 'BankOfHangzhou',
                    ]);
                } else {
                    $matchResults[] = [
                        'recharge_id' => $recharge->id,
                        'recharge_number' => $recharge->recharge_number,
                        'confidence' => $bestMatch ? $bestMatch['confidence'] : 0,
                        'match_type' => 'none',
                        'status' => 'unmatched'
                    ];

                    Log::info('充值未找到匹配', [
                        'recharge_id' => $recharge->id,
                        'best_confidence' => $bestMatch ? $bestMatch['confidence'] : 0,
                        'bank' => 'BankOfHangzhou',
                    ]);
                }
            }

            Log::info('充值匹配算法执行完成', [
                'operation' => 'RUN_RECHARGE_MATCHING',
                'total_recharges' => count($pendingRecharges),
                'matched_count' => $matchedCount,
                'success_rate' => count($pendingRecharges) > 0 ? round($matchedCount / count($pendingRecharges) * 100, 2) : 0,
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => true,
                'total_recharges' => count($pendingRecharges),
                'matched_count' => $matchedCount,
                'unmatched_count' => count($pendingRecharges) - $matchedCount,
                'success_rate' => count($pendingRecharges) > 0 ? round($matchedCount / count($pendingRecharges) * 100, 2) : 0,
                'matches' => $matchResults
            ];

        } catch (\Exception $e) {
            Log::error('充值匹配算法执行失败', [
                'operation' => 'RUN_RECHARGE_MATCHING',
                'error' => $e->getMessage(),
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage(),
                'matched_count' => 0
            ];
        }
    }

    /**
     * 手动确认匹配
     *
     * @param int $rechargeId 充值申请ID
     * @param int $bankDetailId 银行明细ID
     * @param int|null $operatorId 操作人ID
     * @return array 返回操作结果
     */
    public function confirmMatch(int $rechargeId, int $bankDetailId, ?int $operatorId = null): array
    {
        try {
            $recharge = Recharge::find($rechargeId);
            $bankDetail = BankDetailHangzhou::find($bankDetailId);

            if (!$recharge || !$bankDetail) {
                return [
                    'success' => false,
                    'error' => '充值申请或银行明细不存在'
                ];
            }

            // 检查银行明细是否已被匹配
            if ($bankDetail->match_status === 'matched') {
                return [
                    'success' => false,
                    'error' => '银行明细已被其他充值申请匹配'
                ];
            }

            // 标记银行明细为已匹配
            $bankDetail->markAsMatched($rechargeId, 1.0, $operatorId);

            // 更新充值状态
            $recharge->update([
                'status' => Recharge::STATUS_CONFIRMED,
                'updated_by' => $operatorId
            ]);

            Log::info('手动确认匹配成功', [
                'operation' => 'CONFIRM_MATCH',
                'recharge_id' => $rechargeId,
                'bank_detail_id' => $bankDetailId,
                'operator_id' => $operatorId,
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => true,
                'recharge_id' => $rechargeId,
                'bank_detail_id' => $bankDetailId,
                'status' => 'confirmed'
            ];

        } catch (\Exception $e) {
            Log::error('手动确认匹配失败', [
                'operation' => 'CONFIRM_MATCH',
                'recharge_id' => $rechargeId,
                'bank_detail_id' => $bankDetailId,
                'error' => $e->getMessage(),
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * 取消匹配
     *
     * @param int $rechargeId 充值申请ID
     * @param int|null $operatorId 操作人ID
     * @return array 返回操作结果
     */
    public function cancelMatch(int $rechargeId, ?int $operatorId = null): array
    {
        try {
            $recharge = Recharge::find($rechargeId);

            if (!$recharge) {
                return [
                    'success' => false,
                    'error' => '充值申请不存在'
                ];
            }

            // 查找匹配的银行明细
            $bankDetail = BankDetailHangzhou::where('matched_recharge_id', $rechargeId)->first();

            if ($bankDetail) {
                // 取消银行明细匹配
                $bankDetail->unmatch();
            }

            // 重置充值状态
            $recharge->update([
                'status' => Recharge::STATUS_PENDING,
                'updated_by' => $operatorId
            ]);

            Log::info('取消匹配成功', [
                'operation' => 'CANCEL_MATCH',
                'recharge_id' => $rechargeId,
                'bank_detail_id' => $bankDetail ? $bankDetail->id : null,
                'operator_id' => $operatorId,
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => true,
                'recharge_id' => $rechargeId,
                'bank_detail_id' => $bankDetail ? $bankDetail->id : null,
                'status' => 'cancelled'
            ];

        } catch (\Exception $e) {
            Log::error('取消匹配失败', [
                'operation' => 'CANCEL_MATCH',
                'recharge_id' => $rechargeId,
                'error' => $e->getMessage(),
                'bank' => 'BankOfHangzhou',
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * 寻找最佳匹配的银行明细
     *
     * @param Recharge $recharge
     * @param \Illuminate\Support\Collection $bankDetails
     * @return array|null
     */
    private function findBestMatch(Recharge $recharge, $bankDetails): ?array
    {
        $bestMatch = null;
        $bestConfidence = 0;

        foreach ($bankDetails as $detail) {
            $confidence = $this->calculateMatchConfidence($recharge, $detail);

            if ($confidence > $bestConfidence) {
                $bestConfidence = $confidence;
                $bestMatch = [
                    'detail' => $detail,
                    'confidence' => $confidence
                ];
            }
        }

        return $bestMatch;
    }

    /**
     * 计算匹配置信度
     * 基于多维度匹配算法：
     * - 金额匹配度 (40%)
     * - 时间匹配度 (30%)
     * - 银行账号匹配度 (20%)
     * - 付款方信息匹配度 (10%)
     *
     * @param Recharge $recharge
     * @param BankDetailHangzhou $detail
     * @return float
     */
    private function calculateMatchConfidence(Recharge $recharge, BankDetailHangzhou $detail): float
    {
        $scores = [];

        // 1. 金额匹配度 (40%)
        $amountScore = $this->calculateAmountScore($recharge->amount, $detail->amt);
        $scores['amount'] = $amountScore * 0.4;

        // 2. 时间匹配度 (30%)
        $timeScore = $this->calculateTimeScore($recharge->created_at, $detail->transaction_datetime);
        $scores['time'] = $timeScore * 0.3;

        // 3. 银行账号匹配度 (20%)
        $accountScore = $this->calculateAccountScore($recharge->bank_account, $detail->bank_acc);
        $scores['account'] = $accountScore * 0.2;

        // 4. 付款方信息匹配度 (10%)
        $payerScore = $this->calculatePayerScore($recharge, $detail);
        $scores['payer'] = $payerScore * 0.1;

        $totalScore = array_sum($scores);

        Log::debug('匹配置信度计算', [
            'recharge_id' => $recharge->id,
            'bank_detail_id' => $detail->id,
            'scores' => $scores,
            'total_score' => $totalScore,
            'bank' => 'BankOfHangzhou',
        ]);

        return $totalScore;
    }

    /**
     * 计算金额匹配分数
     *
     * @param float $rechargeAmount
     * @param float $detailAmount
     * @return float
     */
    private function calculateAmountScore(float $rechargeAmount, float $detailAmount): float
    {
        if ($rechargeAmount == $detailAmount) {
            return 1.0;
        }

        $diff = abs($rechargeAmount - $detailAmount);
        $maxAmount = max($rechargeAmount, $detailAmount);

        if ($maxAmount == 0) {
            return 0.0;
        }

        $diffPercent = $diff / $maxAmount;

        // 差异在1%以内得0.9分，5%以内得0.5分，超过10%得0分
        if ($diffPercent <= 0.01) {
            return 0.9;
        } elseif ($diffPercent <= 0.05) {
            return 0.5;
        } elseif ($diffPercent <= 0.1) {
            return 0.2;
        }

        return 0.0;
    }

    /**
     * 计算时间匹配分数
     *
     * @param \Carbon\Carbon $rechargeTime
     * @param \Carbon\Carbon $detailTime
     * @return float
     */
    private function calculateTimeScore(\Carbon\Carbon $rechargeTime, \Carbon\Carbon $detailTime): float
    {
        // 银行交易时间应该在充值申请时间之后
        if ($detailTime->lt($rechargeTime)) {
            return 0.0;
        }

        $diffHours = $rechargeTime->diffInHours($detailTime);

        // 1小时内得满分，24小时内线性递减，超过48小时得0分
        if ($diffHours <= 1) {
            return 1.0;
        } elseif ($diffHours <= 24) {
            return 1.0 - (($diffHours - 1) / 23) * 0.5; // 从1.0递减到0.5
        } elseif ($diffHours <= 48) {
            return 0.5 - (($diffHours - 24) / 24) * 0.5; // 从0.5递减到0.0
        }

        return 0.0;
    }

    /**
     * 计算银行账号匹配分数
     *
     * @param string|null $rechargeAccount
     * @param string $detailAccount
     * @return float
     */
    private function calculateAccountScore(?string $rechargeAccount, string $detailAccount): float
    {
        if (empty($rechargeAccount)) {
            return 0.5; // 没有账号信息时给中等分数
        }

        if ($rechargeAccount === $detailAccount) {
            return 1.0;
        }

        // 检查是否为账号的部分匹配（如末尾几位）
        if (strlen($rechargeAccount) >= 4 && strlen($detailAccount) >= 4) {
            $rechargeSuffix = substr($rechargeAccount, -4);
            $detailSuffix = substr($detailAccount, -4);

            if ($rechargeSuffix === $detailSuffix) {
                return 0.7;
            }
        }

        return 0.0;
    }

    /**
     * 计算付款方信息匹配分数
     *
     * @param Recharge $recharge
     * @param BankDetailHangzhou $detail
     * @return float
     */
    private function calculatePayerScore(Recharge $recharge, BankDetailHangzhou $detail): float
    {
        $score = 0.0;

        // 检查银行名称匹配
        if (!empty($recharge->bank_name) && !empty($detail->opp_acc_bank)) {
            if (strpos($detail->opp_acc_bank, $recharge->bank_name) !== false ||
                strpos($recharge->bank_name, $detail->opp_acc_bank) !== false) {
                $score += 0.5;
            }
        }

        // 检查摘要中是否包含充值编号
        if (!empty($detail->abs) && !empty($recharge->recharge_number)) {
            if (strpos($detail->abs, $recharge->recharge_number) !== false) {
                $score += 0.5;
            }
        }

        return min($score, 1.0);
    }
}
